home *** CD-ROM | disk | FTP | other *** search
- /*
- * DemoEditDoc.c
- * Copyright © 1993 Apple Computer Inc. All rights reserved.
- * Portions of this file are revised from CEditDoc.c:
- * Copyright © 1989 Symantec Corporation. All rights reserved.
- * Used by permission.
- *
- * DemoEditDoc is a sub-class to the Think C "TinyEdit"
- * CEditDoc that adds several Digital Signature related
- * commands:
- * cmdOpenSignedFile verifies the signature of an existing,
- * signed, file and opens it, read-only, if successful.
- * Note that, when a file is signed, the Digital
- * Signature Manager marks it "read-only"
- *
- * cmdCloseAndSignFile closes a file (after it was written)
- * and signs it.
- */
- #include <CApplication.h>
- #include <CBartender.h>
- #include <CDataFile.h>
- #include <CError.h>
- #include <TBUtilities.h>
- #include <CWindow.h>
- #include "DemoEditDoc.h"
- #include "CSignedDataFile.h"
- #include <OCEErrors.h>
- #include "Demo.h"
-
- extern OSType gSignature;
- extern CApplication *gApplication;
- extern Boolean gHasDigitalSignatureManager;
-
- void Message(
- const StringPtr textString
- );
- void ErrorMessage(
- OSErr macErr,
- const StringPtr textString
- );
-
- extern CBartender *gBartender; /* The menu handling object */
- extern CError *gError; /* The error handling object */
-
- /*
- * IDemoEditDoc
- * Just do the standard initialization.
- */
- void
- DemoEditDoc::IDemoEditDoc(
- CApplication *aSupervisor,
- Boolean printable
- )
- {
- inherited::IEditDoc(aSupervisor, printable);
- }
-
- /*
- * DoCommand
- * Recognize the "Save, Close, and Sign" menu option.
- */
- void
- DemoEditDoc::DoCommand(
- long theCommand
- )
- {
- switch (theCommand) {
- case cmdCloseAndSignFile:
- this->CloseAndSignFile();
- break;
- default:
- inherited::DoCommand(theCommand);
- break;
- }
- }
-
- /*
- * Activate
- * Override this to enable the Close and Sign document
- * method when the window becomes active.
- */
- void
- DemoEditDoc::Activate(void)
- {
- inherited::Activate();
- if (gHasDigitalSignatureManager)
- gBartender->EnableCmd(cmdCloseAndSignFile);
- }
-
- /*
- * UpdateMenus
- * If this is called, we know that there is a document.
- * If the Digital Signature Manager is available, enable
- * the "Save, Close, and Sign" menu option (it is disabled
- * by default).
- */
- void
- DemoEditDoc::UpdateMenus(void)
- {
- inherited::UpdateMenus();
- if (gHasDigitalSignatureManager)
- gBartender->EnableCmd(cmdCloseAndSignFile);
- }
-
- /*
- * DoSaveAs
- * This subclass to CEditDoc::DoSaveAs only exists
- * to create files with TeachText as their creator.
- * Note, also, that we notice the dupFNErr: you can
- * get this error if you try to Save As on top of
- * a locked file (Sign File creates locked files.)
- */
- Boolean
- DemoEditDoc::DoSaveAs(
- SFReply *macSFReply
- )
- {
- Boolean result;
- OSType oldSignature;
-
- oldSignature = gSignature;
- gSignature = 'ttxt'; /* TeachText */
- TRY {
- result = inherited::DoSaveAs(macSFReply);
- }
- CATCH {
- gSignature = oldSignature;
- if (gLastError == dupFNErr) {
- /*
- * This error appears if you try
- * to Save over a read-only file,
- * selecting "Replace" in the
- * "Replace existing file" dialog.
- */
- Message(
- "\pDuplicate file name error:"
- " please choose a different name."
- " (You cannot replace a read-only file.)"
- );
- gApplication->JumpToEventLoop();
- }
- }
- ENDTRY;
- gSignature = oldSignature;
- return (result);
- }
-
- /*
- * OpenAndVerifyFile
- * Check for a digital signature. If one is found, it is
- * verified and, if successful, the file is opened read-only
- * (Note that signing a file causes it to be "locked" against
- * writes.) If there is no signature, it is opened normally.
- */
- void
- DemoEditDoc::OpenAndVerifyFile(
- SFReply *macSFReply
- )
- {
- CSignedDataFile *aSignedDataFile;
- FSSpec macFSSpec;
- short vRefNum;
- long dirID;
- long procID;
-
- aSignedDataFile = NULL;
- if (gHasDigitalSignatureManager == FALSE) {
- /*
- * We shouldn't get here: the CApplication
- * method should have disabled the "Open Signed
- * File" menu option. If we do, just call our
- * document open read-only method.
- */
- OpenFileReadOnly(macSFReply);
- }
- else {
- /*
- * FIrst, convert the SFReply to a FSSpec.
- * This will crash on System 6 but we don't
- * care as Digital Signatures require System 7.
- */
- FailOSErr(GetWDInfo(
- macSFReply->vRefNum,
- &vRefNum,
- &dirID,
- &procID
- ));
- FailOSErr(FSMakeFSSpec(
- vRefNum,
- dirID,
- macSFReply->fName,
- &macFSSpec
- ));
- /*
- * Create a signature object. If the file is signed, try
- * to verify it. If the file wasn't signed, open it normally.
- * If it was signed, verify it and open it read-only
- * if the verification succeeded.
- */
- aSignedDataFile = new (CSignedDataFile);
- TRY {
- aSignedDataFile->ISignedDataFile();
- if (aSignedDataFile->FileIsSigned(&macFSSpec) == FALSE) {
- /*
- * File wasn't signed. Dispose of the signature
- * context and open the file using the normal
- * method.
- */
- aSignedDataFile->Dispose();
- OpenFile(macSFReply);
- }
- else {
- /*
- * The file is signed. Try to verify it. If
- * successful, we'll display the signer context
- * and open it read-only.
- */
- aSignedDataFile->VerifyFile(
- &macFSSpec, /* File to verify */
- gSIGStatusProc /* Built-in status proc */
- );
- aSignedDataFile->ShowSigner("\p");
- ForgetObject(aSignedDataFile);
- OpenFileReadOnly(macSFReply);
- }
- }
- CATCH {
- /*
- * Oops. Try to display a sensible error message for
- * some of the Digital Signature Manager failure states.
- * The text should, of course, be stored in resources.
- */
- InitCursor();
- switch (gLastError) {
- case userCanceledErr:
- Message("\pUser cancelled verification");
- goto exit;
- case kSIGSignerErr:
- Message("\pThe signature is not valid");
- goto exit;
- case kSIGVerifyFailedErr:
- Message("\pVerification failed");
- exit: ForgetObject(aSignedDataFile);
- HiliteMenu(NOTHING);
- gApplication->JumpToEventLoop();
- break;
- case kSIGInvalidCredentialErr:
- /*
- * Umm, I haven't actually been able to
- * get this message, so the code might
- * be slightly inefficient here.
- */
- Message(
- "\pVerification succeeded, but credentials"
- " are invalid, pending, or expired."
- );
- aSignedDataFile->ShowSigner("\p");
- ForgetObject(aSignedDataFile);
- OpenFileReadOnly(macSFReply);
- NO_PROPAGATE;
- default:
- /*
- * Something is seriously wrong, use the
- * default error message method.
- */
- ForgetObject(aSignedDataFile);
- break;
- }
- }
- ENDTRY;
- }
- }
-
- /*
- * CloseAndSignFile
- * This is an alternative to the normal Close(FALSE)
- * method. It closes the file (which will create/save it if
- * necessary), then signs the object.
- */
- void
- DemoEditDoc::CloseAndSignFile(void)
- {
- CSignedDataFile *aSignedDataFile;
- FInfo fileInfo;
- FSSpec macFSSpec;
-
- if (DoSave()) {
- if (gHasDigitalSignatureManager == FALSE) {
- /*
- * This shouldn't happen (see note in OpenAndVerifyFile
- * above). If we get here however, just do a normal Close.
- */
- this->Close(FALSE);
- }
- else {
- /*
- * Because of the way the Close method operates, we
- * have to grab the file specification before closing
- * the file.
- */
- TRY {
- itsFile->GetFSSpec(&macFSSpec);
- if (this->Close(FALSE)) {
- /*
- * The file closed successfully (i.e., the user
- * didn't Cancel the close). Now, we can sign
- * the contents.
- */
- aSignedDataFile = new (CSignedDataFile);
- aSignedDataFile->ISignedDataFile();
- aSignedDataFile->SignFile(
- NULL, /* No signer file given */
- "\p", /* Default prompt */
- &macFSSpec, /* FileSpec to sign */
- gSIGStatusProc /* Built-in status proc */
- );
- }
- }
- CATCH {
- /*
- * Signing was unsuccessful. Display an
- * error message for some expected errors.
- * The text for these error messages should
- * be stored in resource strings, of course.
- */
- ForgetObject(aSignedDataFile);
- switch (gLastError) {
- case wrPermErr:
- Message(
- "\pCan't write to a read-only file:"
- " please save the file under a different name"
- );
- gApplication->JumpToEventLoop();
- break;
- case userCanceledErr:
- Message(
- "\pUser cancelled signature."
- " File is saved and closed."
- );
- NO_PROPAGATE;
- break;
- case kSIGPasswordErr:
- Message(
- "\pUser entered an incorrect password."
- " File is saved and closed."
- );
- NO_PROPAGATE;
- break;
- case kSIGSignerErr:
- Message("\pSigner error."
- " File is saved and closed."
- );
- NO_PROPAGATE;
- break;
- case kSIGSignerNotValidErr:
- Message(
- "\pInvalid signer."
- " File is saved and closed."
- );
- NO_PROPAGATE;
- break;
- default:
- break;
- }
- }
- ENDTRY;
- }
- }
- }
-
- /*
- * OpenFileReadOnly
- * This is used by DemoEditDoc to open a file
- * without write permission. It is a cut/paste revision of
- * CEditDoc::OpenFile().
- */
- void
- DemoEditDoc::OpenFileReadOnly(
- SFReply *macSFReply
- )
- {
- CDataFile *theFile;
- Handle theData;
- Str63 theName;
- OSErr theError;
-
- /**
- ** Create a file and send it a SFSpecify()
- ** message to set up the name, volume, and
- ** directory.
- **
- **/
-
- theFile = new(CDataFile);
-
- /**
- ** Be sure to set the instance variable
- ** so other methods can use the file if they
- ** need to. This is especially important if
- ** you leave the file open in this method.
- ** If you close the file after reading it, you
- ** should be sure to set itsFile to NULL.
- **
- **/
-
- itsFile = theFile;
-
- theFile->IDataFile();
- theFile->SFSpecify(macSFReply);
-
-
- /**
- ** Send the file an Open() message to
- ** open it. You can use the ReadSome() or
- ** ReadAll() methods to get the contents of the file.
- **
- **/
- theFile->Open(/* fsRdWrPerm */ fsRdPerm);
- if (theFile->GetLength() > 10240L)
- {
- ParamText( "\pCan't open a file this big.", "\p", "\p", "\p");
- PositionDialog('ALRT', 128);
- InitCursor();
- Alert(128, NULL);
-
- Dispose();
- return;
- }
-
-
- theData = theFile->ReadAll(); /* ReadAll() creates the handle */
-
- BuildWindow(theData);
-
- /**
- ** In your application, you'll probably store
- ** the data in some form as an instance variable
- ** in your document class. For this example, there's
- ** no need to save it, so we'll get rid of it.
- **
- **/
-
- DisposHandle(theData);
- itsFile->GetName(theName);
- itsWindow->SetTitle(theName);
- itsWindow->Select(); /* Don't forget to make the window active */
- /*
- * Since we opened the file read-only, we don't want
- * to let the user try to write into the file. The
- * simplest way to prevent this is to dispose of
- * the file object.
- */
- ForgetObject(itsFile);
- }
-
-
-